package com.ms.common.util;

import com.ms.common.exception.BaseException;
import com.ms.common.function.Closure2;
import com.ms.common.reflect.BeanToMapConverter;
import com.ms.common.reflect.SetAccessibleAction;
import com.ms.common.reflect.TypeResolver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.util.ClassUtils;

import javax.management.ReflectionException;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.annotation.Annotation;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.*;
import java.security.AccessController;
import java.util.*;
import java.util.function.BiFunction;
import java.util.function.Function;

/**
 * @author zdh
 */
public class ReflectUtils {

    private static final Logger logger = LoggerFactory.getLogger(ReflectUtils.class);

    // 创建 ConversionService 实例
    private static ConversionService conversionService = new DefaultConversionService();

    public  interface PropertyDescriptorCallback {
        void doWithProperty(PropertyDescriptor propertyDescriptor);
    }

    public static final Class<?>[] EMPTY_CLASSES = new Class[0];

    public static final String READMETHOD_KEY = "get";
    public static final String BOOLEAN_READMETHOD_KEY = "is";
    public static final String WRITEMETHOD_KEY = "set";

    private static final Map<Class<?>, Class<?>> BASE_TYPE_MAPPER;

    static {
        BASE_TYPE_MAPPER = new HashMap<>();
        BASE_TYPE_MAPPER.put(boolean.class, Boolean.class);
        BASE_TYPE_MAPPER.put(char.class, Character.class);
        BASE_TYPE_MAPPER.put(byte.class, Byte.class);
        BASE_TYPE_MAPPER.put(short.class, Short.class);
        BASE_TYPE_MAPPER.put(int.class, Integer.class);
        BASE_TYPE_MAPPER.put(long.class, Long.class);
        BASE_TYPE_MAPPER.put(float.class, Float.class);
        BASE_TYPE_MAPPER.put(double.class, Double.class);
    }

    private ReflectUtils() {
    }


    /**
     * 设置可访问对象的可访问权限为 true
     *
     * @param object 可访问的对象
     * @param <T>    类型
     * @return 返回设置后的对象
     */
    public static <T extends AccessibleObject> T setAccessible(T object) {
        return AccessController.doPrivileged(new SetAccessibleAction<>(object));
    }

    public static <T, ID> void mergeByCheckedIds(
            final Collection<T> srcObjects, final Collection<ID> checkedIds,
            final Class<T> clazz, final String idName) {

        Assert.notNull(srcObjects, "srcObjects不能为null");
        Assert.hasText(idName, "idName不能为null");
        Assert.notNull(clazz, "clazz不能为null");

        if (checkedIds == null) {
            srcObjects.clear();
            return;
        }
        Iterator<T> srcIterator = srcObjects.iterator();
        try {
            while (srcIterator.hasNext()) {
                T element = srcIterator.next();
                Object id;
                id = getPropertyValue(element, idName);

                if (!checkedIds.contains(id)) {
                    srcIterator.remove();
                } else {
                    checkedIds.remove(id);
                }
            }

            for (ID id : checkedIds) {
                T obj = clazz.newInstance();
                setProperty(obj, idName, id);
                srcObjects.add(obj);
            }
        } catch (Exception e) {
            handleReflectionException(e);
        }
    }

    /**
     * 在集合中 查询给定属性名的 属性值
     * @param elements
     * @param propName
     * @param <T>
     * @return
     */
    public static <T> List<T> getProperties(Collection elements, String propName) {
        List<T> values = new ArrayList<>(elements.size());
        T val = null;
        for(Object obj : elements){
            val = (T)getPropertyValue(obj, propName);
            values.add(val);
        }
        return values;
    }

    public static <T> List<T> getProperties(Object[] elements, String propName) {
        List<T> values = new ArrayList<T>(elements.length);
        T val = null;
        for(Object obj : elements){
            val = (T)getPropertyValue(obj, propName);
            values.add(val);
        }
        return values;
    }

    public static Object getPropertyValue(Object element, String propName) {
        return getPropertyValue(element, propName, true);
    }


    /**
     * 获取给定对象 中指定属性名的值，如果根据 属性 throwIfError 决定是否抛出异常
     * @param element
     * @param propName
     * @param throwIfError
     * @return
     */
    public static Object getPropertyValue(Object element, String propName, boolean throwIfError) {
        return getPropertyValue(element, propName, (p, e)->{
            logger.error("get ["+element+"] property["+propName+"] error: " + e.getMessage());
            if(throwIfError) {
                throw new BaseException("get ["+element+"] property["+propName+"] error", e);
            }
        });
    }

    public static  Object getPropertyValue(Object element, String propName, Closure2<String, Exception> errorHandler) {
        if (element instanceof Map) {
            return getValue((Map) element, propName);
        }
        try{
            return new BeanWrapperImpl(element).getPropertyValue(propName);
        }catch(Exception e){
            errorHandler.execute(propName, e);
        }
        return null;
    }


    /**
     * 1、根据Class 和 PropertyDescriptor 获取对于属性的 反射 set Method
     * 2、调用反射方法
     * @param element
     * @param prop
     * @return
     */
    public static Object getProperty(Object element, PropertyDescriptor prop) {
        return invokeMethod(false, ReflectUtils.getReadMethod(element.getClass(), prop), element);

    }

    /**
     * 设置属性值
     * @param element 对象
     * @param prop 属性描述器
     * @param val 值对象
     */
    public static void setProperty(Object element, PropertyDescriptor prop, Object val) {
        Method wmethod = getWriteMethod(element.getClass(), prop);
        if(wmethod==null) {
            throw new BaseException("not write method: " + prop.getName());
        }
        invokeMethod(wmethod, element,  conversionService.convert(val, prop.getPropertyType()));
    }

    protected static Object getValue(Map map, String propName) {
        return ((Map) map).get(propName);
    }

    public static void setProperty(Object element, String propName, Object value) {
        setProperty(element, propName, value, true);
    }


    public static void setProperty(Object element, String propName, Object value, boolean throwIfError) {
        setProperty(element, propName, value, throwIfError, false);
    }

    public static void setProperty(Object element, String propName, Object value, boolean throwIfError, boolean skipIfNoSetMethod) {
        if (element instanceof Map) {
            ((Map) element).put(propName, value);
            return;
        }
        PropertyDescriptor prop = getPropertyDescriptor(element, propName);
        try {
            if (prop == null) {
                throw new BaseException("can not find the property : " + propName);
            }
            if (prop.getPropertyType().isPrimitive() && value == null) {
                throw new BaseException("the property[" + propName
                        + "] type is primitive[" + prop.getPropertyType()
                        + "], the value can not be null");
            }
            if(prop.getWriteMethod()==null){
                if(!skipIfNoSetMethod){
                    throw new NoSuchMethodException("not property[" + propName+"] setter found on class: " + element.getClass());
                }else{
                    return ;
                }
            }
            invokeMethod(prop.getWriteMethod(), element, value);
        } catch (Exception e) {
            if (throwIfError) {
                handleReflectionException(e);
            }
        }
    }

    /**
     * 把给定属性 和属性值 设置对对象中
     * @param element
     * @param propName
     * @param value
     */
    public static void tryToSetProperty(Object element, String propName, Object value) {
        boolean exp = false;
        try {
            //1、
            setProperty(element, propName, value, true);
        } catch (Exception e) {
            exp = true;
        }
        if (exp) {
            exp = false;
            try {
                //2、set方法
                String setMethodName = "set"
                        + propName.substring(0, 1).toUpperCase()
                        + propName.substring(1);
                //3、反射调用
                invokeMethod(setMethodName, element, value);
            } catch (Exception e) {
                exp = true;
            }
        }
        if (exp) {
            exp = false;
            try {
                //4、Field 反射调用
                setBeanFieldValue(propName, element, value);
            } catch (Exception e) {
                exp = true;
            }
        }
        if (exp) {
            throw new BaseException("can not set the property[" + propName
                    + "]'s value");
        }
    }

    public static PropertyDescriptor getPropertyDescriptor(Object element, String propName) {
        return getPropertyDescriptor(element.getClass(), propName);
    }

    public static PropertyDescriptor getPropertyDescriptor(Class<?> element, String propName) {
        return new BeanWrapperImpl(element).getPropertyDescriptor(propName);
    }

    public static boolean isPropertyOf(Object bean, String propName){
        if(bean instanceof Map){
            return ((Map) bean).containsKey(propName);
        }else{
            return getPropertyValue(bean, propName)!=null;
        }
    }

    public static List convertElementPropertyToList(
            final Collection collection, final String propertyName) {
        if (collection == null || collection.isEmpty()) {
            return null;
        }
        List list = new ArrayList();

        try {
            for (Object obj : collection) {
                if (obj == null) {
                    continue;
                }
                list.add(getPropertyValue(obj, propertyName));
            }
        } catch (Exception e) {
            handleReflectionException(e);
        }

        return list;
    }

    public static String convertElementPropertyToString(
            final Collection collection, final String propertyName,
            final String separator) {
        List list = convertElementPropertyToList(collection, propertyName);
        return StringUtils.join(list, separator);
    }

    public static Class<?> getSuperClassGenricType(final Class<?> clazz) {
        return getSuperClassGenricType(clazz, Object.class);
    }

    public static Class<?> getSuperClassGenricType(final Class<?> clazz,
                                                   final Class<?> stopClass) {
        return getSuperClassGenricType(clazz, 0, stopClass);
    }

    /***************************************************************************
     * GenricType handler, copy form spring-side
     *
     * @param clazz
     * @param index
     * @param stopClass
     * @return
     */
    public static Class<?> getSuperClassGenricType(final Class<?> clazz, final int index, Class<?> stopClass) {
        if(clazz.equals(stopClass)) {
            return clazz;
        }

        Type genType = clazz.getGenericSuperclass();

        if (!(genType instanceof ParameterizedType)) {
            if (stopClass!=null && stopClass.isAssignableFrom((Class) genType)) {
                while (!(genType instanceof ParameterizedType)) {
                    genType = ((Class) genType).getGenericSuperclass();
                    if (genType == null) {
                        return Object.class;
                    }
                }
            } else {
                logger.warn(clazz.getSimpleName()
                        + "'s superclass not ParameterizedType");
                return Object.class;
            }
        }

        Type[] params = ((ParameterizedType) genType).getActualTypeArguments();

        if (index >= params.length || index < 0) {
            logger.warn("Index: " + index + ", Size of "
                    + clazz.getSimpleName() + "'s Parameterized Type: "
                    + params.length);
            return Object.class;
        }
        if (!(params[index] instanceof Class)) {
            logger
                    .warn(clazz.getSimpleName()
                            + " not set the actual class on superclass generic parameter");
            return Object.class;
        }

        return (Class<?>) params[index];
    }

    public static Class<?> resolveClassOfGenericType(Class<?> parentGenericType, Type subType) {
        return resolveClassOfGenericType(parentGenericType, subType, 0);
    }

    /***
     * parentGenericType为泛型类，subType为实现或继承了泛型类（parentGenericType）的子类
     * 此方法解释subType实现泛型类时定义的实际类型
     * @author weishao zeng
     * @param parentGenericType parentType
     * @param subType
     * @param subTypeGenericIndex index
     * @return
     */
    public static Class<?> resolveClassOfGenericType(Class<?> parentGenericType, Type subType, final int subTypeGenericIndex) {
        Type subTypeGenericType = TypeResolver.resolveGenericType(parentGenericType, subType);
        Class<?> type = ReflectUtils.getGenricType(subTypeGenericType, subTypeGenericIndex);
        return type;
    }

    public static Class<?> getGenricType(final Object obj, final int index) {
        return getGenricType(obj, index, Object.class);
    }
    public static Class<?> getGenricType(final Object obj, final int index, Class<?> defaultCLass) {

        Class clazz = getObjectClass(obj);
        Type genType = null;
        if(obj instanceof Type){
            genType = (Type) obj;
        }else{
            genType = clazz;
        }

        if (!(genType instanceof ParameterizedType)) {
            return defaultCLass;
        }

        Type[] params = ((ParameterizedType) genType).getActualTypeArguments();

        if (index >= params.length || index < 0) {
            return defaultCLass;
        }

        if(Class.class.isInstance(params[index])){
            return (Class) params[index];
        }else if(ParameterizedType.class.isInstance(params[index])){
            ParameterizedType ptype = (ParameterizedType) params[index];
            return (Class)ptype.getRawType();
        }else{
            return defaultCLass;
        }
    }


    public static Optional<ParameterizedType> getParameterizedType(final Object obj, final int index) {

        Class clazz = getObjectClass(obj);
        Type genType = null;
        if(obj instanceof Type){
            genType = (Type) obj;
        }else{
            genType = (Type) clazz;
        }

        if (!(genType instanceof ParameterizedType)) {
            return Optional.empty();
        }

        Type[] params = ((ParameterizedType) genType).getActualTypeArguments();

        if (index >= params.length || index < 0) {
            return Optional.empty();
        }
        if(ParameterizedType.class.isInstance(params[index])){
            ParameterizedType ptype = (ParameterizedType) params[index];
            return Optional.of(ptype);
        }else{
            return Optional.empty();
        }
    }

    public static Class getListGenricType(final Class clazz) {
        Class genClass = null;
        if (List.class.isAssignableFrom(clazz)) {
            Method method = findMethod(clazz, "get", int.class);
            if (method != null) {
                Type rtype = method.getGenericReturnType();
                if (ParameterizedType.class.isAssignableFrom(rtype.getClass())) {
                    ParameterizedType ptype = (ParameterizedType) rtype;
                    genClass = (Class) ptype.getActualTypeArguments()[0];
                }
            }
        }
        return genClass;
    }

    public static Method findMethod(Class objClass, String name, Class... paramTypes) {
        return findMethod(false, objClass, name, paramTypes);
    }

    public static Method getReadMethod(Class objClass, PropertyDescriptor pd) {
        Method readMethod;
        if (pd.getReadMethod()==null || pd.getReadMethod().isBridge()) {
            readMethod = getReadMethod(objClass, pd.getName(), pd.getPropertyType());
        } else {
            readMethod = pd.getReadMethod();
        }
        return readMethod;
    }

    /**
     * 根据Class 和属性描述器 获取属性的写方法的反射对象，比如属性  name,写方法就是 setName，其反射反方法就是setName 对应的method
     * @param objClass
     * @param pd
     * @return
     */
    public static Method getWriteMethod(Class objClass, PropertyDescriptor pd) {
        Method writeMethod;
        //1、如果属性描述器中写方法为空 或者 写方法是桥接方法，继续虚招
        if (pd.getWriteMethod()==null || pd.getWriteMethod().isBridge()) {
            writeMethod = getWriteMethod(objClass, pd.getName());
        } else {
            //3、属性描述器中写方法存在，直接获取比返回
            writeMethod = pd.getWriteMethod();
        }
        return writeMethod;
    }

    public static Method getReadMethod(Class objClass, String propName, Class returnType) {
        String mName = getReadMethodName(propName, returnType);
        return findPublicMethod(objClass, mName);
    }

    public static Method getWriteMethod(Class objClass, String propName) {
        String mName = getWriteMethodName(propName);
        return findPublicMethod(objClass, mName);
    }

    /**
     * 获取属性的 get 方法，如果式 boolean 获取 isProperty
     * @param propName
     * @param returnType
     * @return
     */
    public static String getReadMethodName(String propName, Class<?> returnType) {
        //1、首字母大写
        String getMethod = StringUtils.capitalize(propName);
        //2、判断属性类型是否是 Boolean 或者 boolean 类型
        if (returnType!=null && Boolean.class.equals(returnType) || boolean.class.equals(returnType)) {
            getMethod = BOOLEAN_READMETHOD_KEY + getMethod;
        } else {
            getMethod = READMETHOD_KEY + getMethod;
        }
        return getMethod;
    }

    /**
     * 获取属性 set 方法
     * @param name
     * @return
     */
    public static String getWriteMethodName(String name) {
        String getMethod = StringUtils.capitalize(name);
        return WRITEMETHOD_KEY + getMethod;
    }

    /**
     * 查找属性 对应的 get 反射方法
     * @param objClass
     * @param field
     * @return
     */
    public static Method findGetMethod(Class objClass, Field field) {
        //1、属性名首字母大写
        String mName = StringUtils.capitalize(field.getName());
        if (field.getType().equals(Boolean.class) || field.getType().equals(boolean.class)) {
            mName = BOOLEAN_READMETHOD_KEY + mName;
        } else {
            mName = READMETHOD_KEY + mName;
        }
        return findMethod(false, objClass, mName);
    }

    /**
     * 获取属性 对应 set 反射方法
     * @param objClass
     * @param field
     * @return
     */
    public static Method findSetMethod(Class objClass, Field field) {
        //1、属性首字母大写
        String mName = StringUtils.capitalize(field.getName());
        mName = WRITEMETHOD_KEY + mName;
        return findMethod(false, objClass, mName);
    }

    /**
     *
     * @param ignoreIfNotFound 如果没有找到是否忽略，即返回空值，否则抛出异常
     * @param objClass 对象 Class 类型
     * @param name      方法名称
     * @param paramTypes    方法参数类型
     * @return
     */
    public static Method findMethod(boolean ignoreIfNotFound, Class objClass, String name, Class... paramTypes) {
        Optional<Method> methodOpt = findMethod(objClass, method->{
            //符合要求即返回true 1）不是桥接方法 2）方法名称与传入的一致 3）参数类型一致
            if (!method.isBridge() && name.equals(method.getName()) && ( LangUtil.isEmpty(paramTypes) || matchParameterTypes(paramTypes, method.getParameterTypes()))) {
                return true;
            }
            return false;
        });
        if(methodOpt.isPresent()){
            return methodOpt.get();
        }else if(ignoreIfNotFound){
            return null;
        }
        throw new BaseException("can not find the method : [class=" + objClass + ", methodName=" + name + ", paramTypes=" +  LangUtil.toString(paramTypes) + "]");
    }

    /**
     * 在给定 Class 或其父类中查找 符合 过滤器的 method
     * @param objClass
     * @param filter
     * @return
     */
    public static Optional<Method> findMethod(Class objClass, Function<Method, Boolean> filter) {
        Assert.notNull(objClass, "objClass must not be null");
        try {
            Class searchType = objClass;
            while (!Object.class.equals(searchType) && searchType != null) {
                Method[] methods = (searchType.isInterface() ? searchType.getMethods() : searchType.getDeclaredMethods());
                for (int i = 0; i < methods.length; i++) {
                    Method method = methods[i];
                    if (filter.apply(method)) {
                        return Optional.of(method);
                    }
                }
                searchType = searchType.getSuperclass();
            }
        } catch (Exception e) {
            handleReflectionException(e);
        }
	
        return Optional.empty();
    }

    /***********
     * find from declared methods in class or parent class
     *
     * @param objClass
     * @param name
     * @return
     */
    public static List<Method> findMethodsByName(Class objClass, String name, Class... paramTypes) {
        Assert.notNull(objClass, "objClass must not be null");
        Assert.notNull(name, "Method name must not be null");
        List<Method> methodList = new ArrayList<Method>();
        try {
            Class searchType = objClass;
            while (!Object.class.equals(searchType) && searchType != null) {
                Method[] methods = (searchType.isInterface() ? searchType.getMethods() : searchType.getDeclaredMethods());
                for (int i = 0; i < methods.length; i++) {
                    Method method = methods[i];
                    if (!method.isBridge() && name.equals(method.getName()) && (LangUtil.isEmpty(paramTypes) || matchParameterTypes(paramTypes, method.getParameterTypes())) ) {
                        methodList.add(method);
                    }
                }
                searchType = searchType.getSuperclass();
            }
        } catch (Exception e) {
            logger.error("findMethodsByName ["+name+"] error : "+e.getMessage());
        }
        return methodList;
    }

    /***********
     *
     * find from public methods
     *
     * @param objClass Class
     * @param name 方法名称
     * @param paramTypes 方法参数
     * @return
     */
    public static List<Method> findPublicMethods(Class objClass, String name, Class... paramTypes) {
        Assert.notNull(objClass, "objClass must not be null");
        Assert.notNull(name, "Method name must not be null");
        List<Method> methodList = new ArrayList<Method>();
        try {
            Method[] methods = objClass.getMethods();
            for (int i = 0; i < methods.length; i++) {
                Method method = methods[i];
                if (!method.isBridge() && name.equals(method.getName()) && ( LangUtil.isEmpty(paramTypes) || matchParameterTypes(paramTypes, method.getParameterTypes())) ) {
                    methodList.add(method);
                }
            }
        } catch (Exception e) {
            logger.error("findPublicMethods ["+name+"] method error : "+e.getMessage());
        }
        return methodList;
    }

    /**
     *
     * @param objClass Class
     * @param name  方法名
     * @param paramTypes 参数类型
     * @return
     */
    public static Method findPublicMethod(Class objClass, String name, Class... paramTypes) {
        try {
            return findPublicMethods(objClass, name, paramTypes).get(0);
        } catch (IndexOutOfBoundsException e) {
            return null;
        }
    }

    public static List<Method> findAnnotationMethods(Class objClass,
                                                     Class<? extends Annotation> annoClasses) {
        Assert.notNull(annoClasses);
        List<Method> methodList = null;
        try {
            Method[] methods = objClass.getMethods();
            for (Method method : methods) {
                if (method.getAnnotation(annoClasses) == null) {
                    continue;
                }
                if (methodList == null) {
                    methodList = new ArrayList<>();
                }
                methodList.add(method);
            }
        } catch (Exception e) {
            handleReflectionException(e);
        }
        return methodList == null ? Collections.EMPTY_LIST : methodList;
    }

    public static Method findUniqueAnnotationMethod(Class objClass,
                                                    Class<? extends Annotation> annoClasses, boolean throwIfMore) {
        Assert.notNull(annoClasses);
        Method method = null;
        try {
            Method[] methods = objClass.getMethods();
            for (Method m : methods) {
                if (m.getAnnotation(annoClasses) == null) {
                    continue;
                }
                if (method != null && throwIfMore) {
                    throw new BaseException("the class[" + objClass
                            + "] has more than one method has the annotaiton["
                            + annoClasses + "]");
                }
                method = m;
            }
        } catch (Exception e) {
            handleReflectionException(e);
        }
        return method;
    }

    /***************************************************************************
     * reflectionException handle, copy from spring
     *
     * @param ex
     */
    public static void handleReflectionException(Exception ex) {
        if (ex instanceof NoSuchMethodException) {
            throw new IllegalStateException("Method not found: "
                    + ex.getMessage());
        }
        if (ex instanceof IllegalAccessException) {
            throw new IllegalStateException("Could not access method: "
                    + ex.getMessage());
        }
        if (ex instanceof InvocationTargetException) {
            handleInvocationTargetException((InvocationTargetException) ex);
        }
        if (ex instanceof RuntimeException) {
            throw (RuntimeException) ex;
        }
        handleUnexpectedException(ex);
    }

    public static void handleInvocationTargetException(
            InvocationTargetException ex) {
        rethrowRuntimeException(ex.getTargetException());
    }

    public static void rethrowRuntimeException(Throwable ex) {
        if (ex instanceof RuntimeException) {
            throw (RuntimeException) ex;
        }
        if (ex instanceof Error) {
            throw (Error) ex;
        }
        handleUnexpectedException(ex);
    }

    private static void handleUnexpectedException(Throwable ex) {
        IllegalStateException isex = new IllegalStateException(
                "Unexpected exception thrown");
        isex.initCause(ex);
        throw isex;
    }

    public static <T> T newInstance(Class<T> clazz) {
        T instance = null;
        try {
            instance = clazz.newInstance();
        } catch (Exception e) {
            throw new BaseException("instance class error : " + clazz, e);
        }
        return instance;
    }


    public static Class<?> loadClass(String className) {
        return loadClass(className, true);
    }

    public static Class<?> loadClass(String className, boolean throwIfError) {
        Class<?> clz = null;
        try {
            clz = Class.forName(className, true, ClassUtils.getDefaultClassLoader());
        } catch (Exception e) {
            if(throwIfError) {
                throw new BaseException("class not found : " + className, e);
            } else {
                logger.warn("class not found : " + className);
            }
        }
        return clz;
    }

    /**
     * 根据给定ClassLoader 和给定 class 名称 加载类
     * @param cl
     * @param className
     * @return
     */
    public static Class<?> loadClass(ClassLoader cl, String className) {
        Class<?> clz = null;
        try {
            clz = cl.loadClass(className);
        } catch (ClassNotFoundException e) {
            throw new BaseException("class not found : " + className, e);
        }
        return clz;
    }

    /**
     * 根据 className 创建实例
     * 1）先加载类
     * 2）在创建实例
     * @param className
     * @param <T>
     * @return
     */
    public static <T> T newInstance(String className) {
        return (T) newInstance(loadClass(className));
    }

    /**
     *
     * @param clsNames ： "className1, className2, className3"
     * @param <T>
     * @return
     */
    public static <T> List<T> toInstanceList(String clsNames) {
        if (StringUtils.isBlank(clsNames)) {
            return Collections.EMPTY_LIST;
        }
        String[] cls = StringUtils.split(clsNames, ",");
        T inst = null;
        List list = new ArrayList();
        for (String c : cls) {
            inst = ReflectUtils.newInstance(c);
            if (inst != null) {
                list.add(inst);
            }
        }
        return list;
    }

    public static <T> T newInstance(Class<T> clazz, Object... objects) {
        T instance = null;
        try {
            Constructor<T>[] constructs = (Constructor<T>[]) clazz
                    .getDeclaredConstructors();
            boolean appropriateConstractor = false;
            for (Constructor<T> constr : constructs) {
                if (matchConstructor(constr, objects)) {
                    constr.setAccessible(true);
                    instance = constr.newInstance(objects);
                    appropriateConstractor = true;
                    break;
                }
            }
            if (appropriateConstractor == false && instance == null) {
                StringBuilder sb = new StringBuilder(
                        "can not find the appropriate constructor, class: ")
                        .append(clazz.getName()).append(", args: ");
                if (objects != null) {
                    for (Object o : objects) {
                        sb.append(o.getClass().getName()).append(" ");
                    }
                }
                throw new BaseException(sb.toString());
            }
        } catch (Exception e) {
            throw new BaseException("instantce class error : " + clazz, e);
        }
        return instance;
    }

    public static boolean matchConstructor(Constructor constr,Object... objects) {
        Class[] pclass = constr.getParameterTypes();
        if (objects.length != pclass.length) {
            return false;
        }
        int index = 0;
        for (Class cls : pclass) {
            if (!hasImplements(objects[index], cls)) {
                return false;
            }
            index++;
        }
        return true;
    }

    /**
     * 比较 两个属性内 元素类型是否一致（前者，即源类型可以转换成目标类型？）
     * @param sourceTypes
     * @param targetTypes
     * @return
     */
    public static boolean matchParameterTypes(Class<?>[] sourceTypes, Class<?>[] targetTypes) {
        if (sourceTypes.length != targetTypes.length) {
            return false;
        }
        int index = 0;
        for (Class<?> cls : targetTypes) {
            if (!cls.isAssignableFrom(sourceTypes[index])) {
                return false;
            }
            index++;
        }
        return true;
    }

    public static boolean matchParameters(Class[] paramTypes, Object[] params) {
        if(LangUtil.isEmpty(params)){
            return LangUtil.isEmpty(paramTypes);
        }
        if (paramTypes.length != params.length) {
            return false;
        }
        int index = 0;
        for (Class cls : paramTypes) {
            if (!cls.isInstance(params[index])){
                if(cls.isPrimitive() && BASE_TYPE_MAPPER.get(cls).isInstance(params[index])){
                    return true;
                }else{
                    return false;
                }
            }
            index++;
        }
        return true;
    }

    public static Class<?> getBoxingType(Class<?> primitiveType){
        if(!primitiveType.isPrimitive()) {
            return primitiveType;
        }
        return BASE_TYPE_MAPPER.get(primitiveType);
    }

    public static boolean hasImplements(Object obj, Class clazz) {
        return clazz.isAssignableFrom(getObjectClass(obj));
    }

    public static PropertyDescriptor findProperty(Class<?> clazz,String propName) {
        BeanInfo beanInfo = null;
        try {
            beanInfo = Introspector.getBeanInfo(clazz, Object.class);
        } catch (Exception e) {
            throw new BaseException(e);
        }
        for (PropertyDescriptor prop : beanInfo.getPropertyDescriptors()) {
            if (propName.equals(prop.getName())) {
                return prop;
            }
        }
        return null;
    }

    public static PropertyDescriptor[] desribProperties(Class<?> clazz) {
        return new BeanWrapperImpl(clazz).getPropertyDescriptors();
    }


    /**
     * 根据是否获取所有字段的布尔标志，获取类的字段并以属性名为键、属性 Field 为值存入 Map。
     *
     * @param clazz           要检查的类
     * @param includeInherited 是否包含继承字段
     * @return 字段名与字段对象的映射
     */
    public static Map<String, Field> getFieldsMap(Class<?> clazz, boolean includeInherited) {
        Map<String, Field> fieldsMap = new HashMap<>();
        if (clazz == null) {
            return fieldsMap;
        }

        // 获取当前类中声明的所有字段，并添加到 map 中
        for (Field field : clazz.getDeclaredFields()) {
            fieldsMap.put(field.getName(), field);
        }

        // 如果需要包含继承字段，则递归获取父类字段
        if (includeInherited) {
            Class<?> superClass = clazz.getSuperclass();
            if (superClass != null && !superClass.equals(Object.class)) {
                fieldsMap.putAll(getFieldsMap(superClass, true));
            }
        }

        return fieldsMap;
    }

    /****
     * 把对象转为map，对象的属性名称为key，对应属性的值为value
     * @author wayshall
     * @param obj
     * @return
     */
    public static Map<String, Object> toMap(Object obj) {
        return toMap(true, obj);
    }

    public static Map<String, Object> toMap(Class<? extends Annotation> annoClass, Annotation anno) {
        Method[] methods = annoClass.getDeclaredMethods();
        Map<String, Object> attrs = new HashMap<>();
        for(Method method : methods){
            Object val = ReflectUtils.invokeMethod(method, anno);
            attrs.put(method.getName(), val);
        }
        return attrs;
    }

    public static Map<String, Object> toMap(boolean ignoreNull, Object obj) {
        return ignoreNull?BeanToMapConverter.beanToMapIgnoreNullValue(obj):BeanToMapConverter.beanToMap(obj);
    }


    public static Map<String, String> toStringMap(boolean ignoreNull, Object obj) {
        Map<String, Object> map = toMap(ignoreNull, obj);
        Map<String, String> rsMap = new HashMap<>();
        map.forEach((k, v)->{
            rsMap.put(k, v==null?null:v.toString());
        });
        return rsMap;
    }

    public static void listProperties(Class objClass, PropertyDescriptorCallback pdcb) {
        Assert.notNull(objClass);
        PropertyDescriptor[] props = desribProperties(objClass);
        if (props == null || props.length == 0) {
            return ;
        }
        for (PropertyDescriptor prop : props) {
            pdcb.doWithProperty(prop);
        }
    }

    /***
     * 实例化一个UserEntity对象，并把map的值设置到UserEntity对象
     * @author
     * @param map
     * @param beanClass
     * @return
     */
    public static <T> T fromMap(Map<String, Object> map, Class<T> beanClass){
        T bean = newInstance(beanClass);
        if( LangUtil.isEmpty(map)) {
            return bean;
        }
        for(Map.Entry<String, Object> entry : map.entrySet()){
            setExpr(bean, entry.getKey(), entry.getValue());
        }
        return bean;
    }

    /****
     * 把src对应字段的值复制到dest
     * @author wayshall
     * @param src
     * @param dest
     * @param seperator
     * @param ignoreNull
     */
    public static void copyFields(Object src, Object dest, char seperator, boolean ignoreNull){
        Map<String, String> mappedFields = ReflectUtils.mappedFields(src.getClass(), dest.getClass(), seperator);
        Object fvalue = null;
        for(Map.Entry<String, String> field : mappedFields.entrySet()){
            fvalue = getFieldValue(src, field.getKey());
            if(fvalue==null && ignoreNull) {
                continue;
            }
            setFieldValue(dest, field.getValue(), fvalue);
        }
    }

    public static Map<String, Object> field2Map(Object obj) {
        return field2Map(obj, (f, v)->v!=null);
    }
    public static Map<String, Object> field2Map(Object obj, BiFunction<Field, Object, Boolean> acceptor) {
        if (obj == null) {
            return Collections.EMPTY_MAP;
        }
        Collection<Field> fields = findFieldsFilterStatic(obj.getClass());
        if (fields == null || fields.isEmpty()) {
            return Collections.EMPTY_MAP;
        }
        Map<String, Object> rsMap = new HashMap();
        Object val = null;
        for (Field field : fields) {
            val = getFieldValue(field, obj, false);
            if (acceptor.apply(field, val)) {
                rsMap.put(field.getName(), val);
            }
        }
        return rsMap;
    }

    public static List<PropertyDescriptor> desribProperties(Class<?> clazz, Class<? extends Annotation> excludeAnnoClass) {
        PropertyDescriptor[] props = desribProperties(clazz);
        List<PropertyDescriptor> propList = new ArrayList<PropertyDescriptor>();
        Method method = null;
        for (PropertyDescriptor prop : props) {
            method = prop.getReadMethod();
            if (method == null
                    || method.getAnnotation(excludeAnnoClass) != null) {
                continue;
            }
            propList.add(prop);
        }
        return propList;
    }

    public static Collection<Field> findFieldsFilterStatic(Class clazz) {
        return findFieldsExcludeAnnotationStatic(clazz, null);
    }

    public static Collection<String> findInstanceFieldNames(Class clazz) {
        return findInstanceFieldNames(clazz, List.class);
    }

    public static Collection<String> findInstanceFieldNames(Class clazz, Class<? extends Collection> collectionClass) {
        Collection<String> fieldNames = newCollections(collectionClass);
        Collection<Field> fields = findFieldsFilterStatic(clazz);
        for(Field f :fields){
            fieldNames.add(f.getName());
        }
        return fieldNames;
    }

    public static <T> Collection<T> newCollections(Class<? extends Collection> clazz){
        return CUtils.newCollections(clazz);
    }

    public static <T extends Collection> T newList(Class<T> clazz){
        if(!List.class.isAssignableFrom(clazz)) {
            throw new BaseException("class must be a List type: " + clazz);
        }
        if(clazz==List.class){
            return (T)new ArrayList();
        }else{
            return newInstance(clazz);
        }
    }

    public static Collection<Field> findFieldsExcludeAnnotationStatic(
            Class clazz, Class<? extends Annotation> excludeAnnotation) {
        return findFieldsExclude(clazz, new Class[] { excludeAnnotation },
                "static ", "transient ", ".this$");
    }

    public static Collection<Field> findFieldFilter(Class clazz, String... filterString) {
        return findFieldsExclude(clazz, null, filterString);
    }

    /**
     * 查找 非静态与非 瞬态字段
     * @param clazz
     * @return
     */
    public static Collection<Field> findNotStaticAndTransientFields(Class clazz) {
		List<Class<?>> classes = findSuperClasses(clazz);
		classes.add(0, clazz);
		Collection<Field> fields = null;
		Field[] fs;
		for (Class cls : classes) {
			fs = cls.getDeclaredFields();
			for (Field f : fs) {
				if(Modifier.isTransient(f.getModifiers()) || Modifier.isStatic(f.getModifiers())) {
                    continue;
                }
				fields.add(f);
			}
		}
		return fields;
    }

    /**
     *
     * @param clazz
     * @param excludeAnnoClasses 排除被某些注解注释的字段
     * @param filterString
     * @return
     */
    public static Collection<Field> findFieldsExclude(Class clazz, Class<? extends Annotation>[] excludeAnnoClasses,String... filterString) {
        //1、获取所有类集合list
        List<Class<?>> classes = findSuperClasses(clazz);
        classes.add(0, clazz);
        //2、
        Collection<Field> fields = new HashSet<>();
        Field[] fs = null;
        for (Class cls : classes) {
            //3、获取class 的 Field集合
            fs = cls.getDeclaredFields();
            for (Field f : fs) {
                if (filterString != null && StringUtils.indexOfAny(f.toString(), filterString) != -1) {
                    //5、f.toString 遇到过滤字符串数组，继续下一循环
                    continue;
                }
                if (excludeAnnoClasses != null) {
                    for (Class<? extends Annotation> annoCls : excludeAnnoClasses) {
                        //6、Field 中是否存在被 excludeAnnoClasses中某些注解注释，存在，则继续下一循环
                        if (annoCls == null || f.getAnnotation(annoCls) != null) {
                            continue;
                        }
                    }
                }
                fields.add(f);
            }
        }
        return fields;
    }

    public static Map toMap(Object objs, String keyName) {
        return toMap(objs, keyName, null);
    }

    /**
     * @param objs 对象，可能数数组、map、list、bean
     * @param keyName  属性名
     * @param valName 默认值
     * @return
     */
    public static Map toMap(Object objs, String keyName, String valName) {
        //1、对象转换为List
        List datas =   CUtils.tolist(objs, true, CUtils.NULL_LIST);
        if (datas == null || datas.isEmpty()) {
            return Collections.EMPTY_MAP;
        }
        Object key;
        Map results = new HashMap();
        for (Object obj : datas) {
            //2、根据对象、对像属性名获取属性值
            key = getExpr(obj, keyName);
            if (key != null) {
                //3、属性值作为key,传入对值
                results.put(key, StringUtils.isBlank(valName) ? obj : getExpr(obj, valName));
            }
        }
        return results;
    }


    public static Field findDeclaredField(Class clazz, String fieldName) {
        try {
            return clazz.getDeclaredField(fieldName);
        } catch (Exception e) {
            logger.warn("findDeclaredField error : "+e.getMessage());
        }
        return null;
    }

    /**
     * 根据 Class 和 fieldName 获取 Field
     * @param clazz
     * @param fieldName
     * @return
     */
    public static Field findField(Class clazz, String fieldName) {
        return findField(clazz, fieldName, false);
    }

    public static Field findField(Class clazz, String fieldName, boolean throwIfNotFound) {
        Field field = findDeclaredField(clazz,fieldName);
        if (field==null && throwIfNotFound) {
            throw new BaseException("can not find class[" + clazz + "]'s field [" + fieldName + "]");
        }
        return field;
    }

    public static List<Field> findAllFields(Class clazz) {
        return new ArrayList<>(getAllFields(clazz).values());
    }

    /**
     * 根据 clazz 和 field类型 获取 Field集合
     * @param clazz
     * @param fieldType
     * @param throwIfNotFound
     * @return
     */
    public static Collection<Field> findFieldsByType(Class clazz, Class fieldType, boolean throwIfNotFound) {

        List<Class<?>> classes = findSuperClasses(clazz);
        classes.add(0, clazz);

        Field[] fs = null;
        Collection<Field> fields = new HashSet<>();
        for (Class cls : classes) {
            fs = cls.getDeclaredFields();
            for (Field f : fs) {
                if (f.getType().isAssignableFrom(fieldType)){
                    fields.add(f);
                }
            }
        }
        if (fields.isEmpty() && throwIfNotFound) {
            throw new BaseException("can not find class[" + clazz
                    + "]'s fieldType [" + fieldType + "]");
        }
        return fields;
    }

    /**
     * 获取对象属性名称列表
     * @param obj
     * @return
     */
    public static List<String> getPropertiesName(Object obj) {
        if (obj instanceof Map) {
            return new ArrayList<String>(((Map) obj).keySet());
        } else {
            return desribPropertiesName(obj,false);
        }
    }

    /**
     * 获取对象的所有属性名称。
     *
     * @param obj             要检查的对象实例
     * @param includeInherited 是否包含继承字段
     * @return 属性名称列表
     */
    public static List<String> desribPropertiesName(Object obj, boolean includeInherited) {
        if (obj == null) {
            return Collections.emptyList();
        }
        Class<?> clazz = obj.getClass();
        Set<String> propertyNames = new LinkedHashSet<>(); // 使用 LinkedHashSet 保持顺序并去重
        getAllFields(clazz, includeInherited).forEach(field -> propertyNames.add(field.getName()));
        return new ArrayList<>(propertyNames);
    }


    /**
     * 根据是否获取所有字段的布尔标志，获取类的字段。
     *
     * @param clazz           要检查的类
     * @param includeInherited 是否包含继承字段
     * @return 字段集合
     */
    private static Set<Field> getAllFields(Class<?> clazz, boolean includeInherited) {
        Set<Field> fields = new LinkedHashSet<>();
        Class<?> currentClass = clazz;

        while (currentClass != null && !currentClass.equals(Object.class)) {
            for (Field field : currentClass.getDeclaredFields()) {
                fields.add(field); // 后添加的字段会覆盖同名的父类字段
            }
            if (!includeInherited) {
                break; // 如果不需要包含继承字段，则只处理当前类后退出循环
            }
            currentClass = currentClass.getSuperclass();
        }

        return fields;
    }


    public static List<Class<?>> findSuperClasses(Class clazz) {
        return ReflectUtils.findSuperClasses(clazz,Object.class);
    }

    /**
     * 获取 知道超类
     * @param clazz
     * @param stopClass
     * @return
     */
    public static List<Class<?>> findSuperClasses(Class clazz, Class stopClass) {
        return CUtils.findSuperClasses(clazz,stopClass);
    }

    public static Object invokeMethod(String methodName, Object target, Object... args) {
        Method m = findMethod(getObjectClass(target), methodName, findTypes(args));
        return invokeMethod(m, target, args);
    }

    public static Object checkAndInvokeMethod(String methodName, Object target, Object... args) {
        Method m = findMethod(true, getObjectClass(target), methodName, findTypes(args));
        if(m==null){
            logger.info("method not found and ignore: " + methodName);
            return null;
        }
        return invokeMethod(m, target, args);
    }

    /***
     * 如果target是class，直接返回
     * @param target
     * @return
     */
    public static <T> Class<T> getObjectClass(Object target) {
        if(target==null) {
            return null;
        }
        Class targetClass = null;
        if (target instanceof Class) {
            targetClass = (Class) target;
        } else {
            targetClass = target.getClass();
        }
        return targetClass;
    }

    public static Class<?>[] findTypes(Object... args) {
        Class<?>[] argTypes = null;
        if (args != null) {
            for (Object arg : args) {
                if (arg == null) {
                    continue;
                }
                Class<?> t = arg.getClass();
                argTypes = (Class<?>[]) ArrayUtils.add(argTypes, t);
            }
        }
        return argTypes;
    }

    public static Object invokeMethod(String methodName, Object target) {
        return invokeMethod(findMethod(target.getClass(), methodName,
                (Class[]) null), target, (Object[]) null);
    }

    public static Object invokeMethod(boolean throwIfError, Method method,Object target) {
        return invokeMethod(throwIfError, method, target, (Object[]) null);
    }

    public static Object invokeMethod(Method method, Object target) {
        return invokeMethod(method, target, (Object[]) null);
    }

    public static Object invokeMethod(Method method, Object target, Object... args) {
        return invokeMethod(true, method, target, args);
    }

    /**
     * 反射调用方法
     * @param throwIfError
     * @param method
     * @param target
     * @param args
     * @return
     */
    public static Object invokeMethod(boolean throwIfError, Method method, Object target, Object... args) {
        try {
            if (!method.isAccessible()) {
                method.setAccessible(true);
            }
            return method.invoke(target, args);
        } catch (Exception ex) {
            if (throwIfError) {
                throw new BaseException("invoke target["+target+"] method[" + method + "] error: " + ex.getMessage(), ex);
            } else {
                return null;
            }
        }
    }

    /*****
     * @see #setFieldValue
     * @param fieldName
     * @param obj
     * @param value
     */
    @Deprecated
    public static void setBeanFieldValue(String fieldName, Object obj, Object value) {
        setFieldValue(obj, fieldName, value);
    }

    /**
     * 根据 对象、字段名、给定属性值，设置字段属性值
     * @param obj
     * @param fieldName
     * @param value
     */
    public static void setFieldValue(Object obj, String fieldName, Object value) {
        //1、根据 Class、fieldName 查找 Field
        Field field = findField(getObjectClass(obj), fieldName, true);
        setFieldValue(obj, field, value);
    }

    /**
     * @param obj
     * @param fieldType
     * @param value
     */
    public static void setFieldValue(Object obj, Class fieldType, Object value) {
        findFieldsByType(getObjectClass(obj), fieldType, true).forEach(f->setFieldValue(obj, f, value));
    }

    public static void setFieldValue(Object obj, Field f, Object value) {
        Assert.notNull(f);
        try {
            if (!f.isAccessible()) {
                f.setAccessible(true);
            }
            f.set(obj, value==null?null:conversionService.convert(value,f.getType()));
        } catch (Exception ex) {
            throw  LangUtil.asBaseException("invoke method error: " + ex.getMessage(), ex);
        }
    }

    @Deprecated
    public static void setBeanFieldValue(Field f, Object obj, Object value) {
        setFieldValue(obj, f, value);
    }

    public static Object getFieldValue(Object obj, String fieldName) {
        if (obj instanceof Map) {
            return getValue((Map) obj, fieldName);
        }
        return getFieldValue(obj, fieldName, true);
    }

    public static Object getFieldValue(Object obj, String fieldName, boolean throwIfError) {
        Field f = findField(getObjectClass(obj), fieldName, throwIfError);
        return f==null?null:getFieldValue(f, obj, throwIfError);
    }

    public static Object getFieldValue(Field f, Object obj, boolean throwIfError) {
        Assert.notNull(f);
        try {
            if (!f.isAccessible()) {
                f.setAccessible(true);
            }
            return f.get(obj);
        } catch (Exception ex) {
            if (throwIfError) {
                throw new BaseException("get value of field[" + f + "] error: " + ex.getMessage(), ex);
            } else {
                return null;
            }
        }
    }

    public static void setFieldValueBySetter(Object obj, String fieldName,
                                             Object value, boolean throwIfError) {
        Field f = findField(getObjectClass(obj), fieldName);
        setFieldValueBySetter(obj, f, value, throwIfError);
    }

    public static Object getFieldValueByGetter(Object obj, String fieldName,
                                               boolean throwIfError) {
        Field f = findField(getObjectClass(obj), fieldName);
        return getFieldValueByGetter(obj, f, throwIfError);
    }

    public static Object getFieldValueByGetter(Object obj, Field f,
                                               boolean throwIfError) {
        try {
			/*String getterName = "get"
					+ org.onetwo.common.utils.StringUtils.toCamel(f
							.getName(), true);*/
            Method getter = findGetMethod(getObjectClass(obj), f);//findMethod(getObjectClass(obj), getterName);
            if(getter==null && throwIfError){
                throw new BaseException("can not find getter for field: "+f.getName()+", class:"+obj.getClass());
            }
            Object val = invokeMethod(getter, obj);
            return val;
        } catch (BaseException ex) {
            throw ex;
        } catch (Exception ex) {
            if (throwIfError) {
                throw new BaseException("get value of field[" + f
                        + "] error: " + ex.getMessage(), ex);
            } else {
                return null;
            }
        }
    }

    public static void setFieldValueBySetter(Object obj, Field f, Object value,
                                             boolean throwIfError) {
        try {
			/*String setterName = WRITEMETHOD_KEY
					+ org.onetwo.common.utils.StringUtils.toCamel(f
							.getName(), true);
			Method setter = findMethod(getObjectClass(obj), setterName, f.getType());*/
            Method setter = findSetMethod(getObjectClass(obj), f);
            if(setter==null && throwIfError){
                throw new BaseException("can not find setter for field: "+f.getName()+", class:"+obj.getClass());
            }
            invokeMethod(setter, obj, value);
        } catch (BaseException ex) {
            throw ex;
        } catch (Exception ex) {
            if (throwIfError) {
                throw new BaseException("set value of field[" + f+ "] error: " + ex.getMessage(), ex);
            }
        }
    }

    /**
     * 设置静态字段值
     * @param clazz
     * @param fieldName
     * @param value
     * @throws NoSuchFieldException
     * @throws IllegalAccessException
     */
    public static void setStaticFieldValue(Class clazz, String fieldName,Object value) throws NoSuchFieldException, IllegalAccessException {
        Field field = findField(clazz, fieldName, true);
        field.setAccessible(true);
        Field modifiersField = Field.class.getDeclaredField("modifiers");
        modifiersField.setAccessible(true);
        modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
        field.set(null, value);
    }


    public static Object getStaticFieldValue(Class clazz, String fieldName) {
        Field field = findField(clazz, fieldName, true);
        return getFieldValue(field, clazz, true);
    }

    public static boolean isEqualsMethod(Method method) {
        if (method == null || !method.getName().equals("equals")) {
            return false;
        }
        Class[] paramTypes = method.getParameterTypes();
        return (paramTypes.length == 1 && paramTypes[0] == Object.class);
    }

    public static boolean isHashCodeMethod(Method method) {
        return (method != null && method.getName().equals("hashCode") && method
                .getParameterTypes().length == 0);
    }

    public static boolean isToStringMethod(Method method) {
        return (method != null && method.getName().equals("toString") && method
                .getParameterTypes().length == 0);
    }

    /**
     * 根据 对象 及 对象中某个属性名 获取属性值
     * @param bean
     * @param name
     * @return
     */
    public static Object getExpr(Object bean, String name) {
        return getExpr(bean, name, false);
    }

    /************
     *
     * @param bean
     * @param name this-property  to thisProperty
     * @param newIfNull 如何
     * @return
     */
    public static Object getExpr(Object bean, String name, boolean newIfNull) {
        Assert.notNull(bean,"bean must not be null");
        Assert.hasText(name,"property name must not be null");
        //1、
        Object parentObj = bean;
        //2、user . to split name
        String[] paths = StringUtils.split(name, ".");
        Object pathObj = null;
        for (String path : paths) {
            if (path.indexOf('-') != -1) {
                //3、按照分隔符 op 把字符串 str转成按单词排列的首字母大写，比如 property-name 转成 propertyName
                path = StringUtils.toCamel(path, '-', false);
            }
            if (parentObj == null) {
                LangUtil.throwBaseException("expr[" + name + "] parent object can not be null : " + path);
            }

            if(parentObj instanceof Map){
                //4、map
                pathObj = getValue((Map)parentObj, path);
            }else{
                //5、获取属性描述器
                PropertyDescriptor pd = getPropertyDescriptor(parentObj, path);
                if(pd!=null){
                    // 6、先从属性反射方法获取属性值 property first
                    pathObj = getProperty(parentObj, pd);
                    if(pathObj==null && newIfNull){
                        //7、创建属性对象，再获取
                        pathObj = newInstance(pd.getPropertyType());
                        setProperty(parentObj, pd, pathObj);
                    }
                }else{
                    //7、属性描述符为null,获取 属性Field
                    Field f = findField(parentObj.getClass(), path);
                    if(f!=null){
                        pathObj = getFieldValue(f, parentObj, true);
                        if(pathObj==null && newIfNull){
                            pathObj = newInstance(f.getType());
                            setBeanFieldValue(f, parentObj, pathObj);
                        }
                    }else{
//							pathObj = invokeMethod(path, parentObj);
                    }
                }
            }
            parentObj = pathObj;
        }
        return pathObj;
    }


    public static void setExpr(Object bean, String name, Object value) {
        setExpr(bean, name, value, false);
    }

    public static void setExpr(Object bean, String name, Object value, boolean tryMethod) {
        Assert.notNull(bean, "bean can not be null");
        Assert.hasText(name, "name must has text");
        int lastDot = name.lastIndexOf('.');
        String setPropertyName = "";
        Object parentObj = bean;
        if(lastDot==-1){
            setPropertyName = name;
        }else{
            String targetObjPath = "";
            setPropertyName = name.substring(lastDot+1);
            targetObjPath = name.substring(0, lastDot);
            parentObj = getExpr(bean, targetObjPath, true);
        }
        if(parentObj instanceof Map){
            ((Map)parentObj).put(setPropertyName, value);
        }else{
            PropertyDescriptor pd = getPropertyDescriptor(parentObj, setPropertyName);
            if(pd!=null){// property first
                setProperty(parentObj, pd, value);
            }else{
                Field f = findField(parentObj.getClass(), setPropertyName, false);
                if(f!=null){
                    setBeanFieldValue(f, parentObj, value);
                }else{
                    if(tryMethod && value!=null){
                        Method mehtod = findMethod(true, getObjectClass(parentObj), setPropertyName, findTypes(value));
                        if(mehtod!=null) {
                            invokeMethod(setPropertyName, parentObj, value);
                        } else {
                            LangUtil.throwBaseException("set ["+bean.getClass().getSimpleName() +": "+bean+"] 's value error by expr : " + name);
                        }
                    }
                }
            }
        }
    }

    public static void setStringDefaultValue(Object inst, String val) {
        setFieldsDefaultValue(inst, String.class, val);
    }

    public static void setFieldsDefaultValue(Object inst, Object... objects) {
        Map properties = CUtils.asMap(objects);
        setFieldsDefaultValue(inst, properties);
    }

    /********
     * 根据map的设置来设置默认值
     * @param inst
     * @param properties
     */
    public static void setFieldsDefaultValue(Object inst, Map properties) {
        Collection<Field> fields = ReflectUtils.findFieldsFilterStatic(inst
                .getClass());
        if (fields == null || fields.isEmpty()) {
            return;
        }
        // Map properties = M.c(objects);
        for (Field f : fields) {
            if (properties.containsKey(f.getName())) {
                ReflectUtils.setBeanFieldValue(f, inst, processValue(f, properties.get(f.getName())));
                continue;
            }
            if (properties.containsKey(f.getType())) {
                ReflectUtils.setBeanFieldValue(f, inst, processValue(f, properties.get(f.getType())));
                continue;
            }
        }
    }

    /*****
     * 如果是:name，返回字段名称，否则返回传入的值；
     * @param field
     * @param val
     * @return
     */
    protected static Object processValue(Field field, Object val) {
        if (!(val instanceof String)) {
            return val;
        }
        Object newVal = val;
        if (val.toString().equals(":name")) {
            newVal = field.getName();
        }
        return newVal;
    }


    public static PropertyDescriptor newProperty(Class clazz, String propName){
        try {
            return new PropertyDescriptor(propName, clazz);
        } catch (IntrospectionException e) {
             LangUtil.throwBaseException("newProperty error : " + e.getMessage(), e);
        }
        return null;
    }

    public static PropertyDescriptor newProperty(String name, Method rMethod, Method wMethod){
        try {
            return new PropertyDescriptor(name, rMethod, wMethod);
        } catch (IntrospectionException e) {
             LangUtil.throwBaseException("create property["+name+"] error : " + e.getMessage(), e);
        }
        return null;
    }

    public static PropertyDescriptor newProperty(Class<?> entityClass, Field field){
        try {
            Method rMethod = ReflectUtils.getReadMethod(entityClass, field.getName(), field.getType());
            Method wMethod = ReflectUtils.getWriteMethod(entityClass, field.getName());
            return new PropertyDescriptor(field.getName(), rMethod, wMethod);
        } catch (IntrospectionException e) {
             LangUtil.throwBaseException("newProperty["+entityClass+"."+field.getName()+"] error : " + e.getMessage(), e);
        }
        return null;
    }

    public static Class<?>[] getObjectClasses(Object[] objs){
        if( LangUtil.isEmpty(objs)) {
            return EMPTY_CLASSES;
        }
        List<Class<?>> clslist = new ArrayList<Class<?>>(objs.length);
        for(Object obj : objs){
            if(obj==null) {
                continue;
            }
            clslist.add(getObjectClass(obj));
        }
        return clslist.toArray(new Class[clslist.size()]);
    }

    /*****
     * 返回src和dest实例字段的交集，如果src的字段名称包含有分隔符separator，则把分隔符转为驼峰格式的名称再查找交集<br/>
     * 如src有字段field_name1，而target有字段fieldName1，则转为fieldName1，并匹配target对应的字段fieldName1
     * @param srcClass
     * @param destClass
     * @param separator src单词之间的分隔符
     * @return
     */
    public static Map<String, String> mappedFields(Class<?> srcClass, Class<?> destClass, char separator){
        Collection<String> srcFields = findInstanceFieldNames(srcClass, Set.class);
        Collection<String> desctFields = findInstanceFieldNames(destClass, Set.class);
        Map<String, String> mappingFields =  new HashMap<>();
        for(String fname : srcFields){
            if(desctFields.contains(fname)){
                mappingFields.put(fname, fname);

            }else if(fname.indexOf(separator)!=-1){
                String destname = StringUtils.toCamel(fname, separator, false);
                if(desctFields.contains(destname)){
                    mappingFields.put(fname, destname);
                }
            }
        }
        return mappingFields;
    }

    public static Class<?> getFinalDeclaringClass(Class<?> innerClass){
        Class<?> parentClass = innerClass.getDeclaringClass();
        while(parentClass!=null && parentClass.getDeclaringClass()!=null) {
            parentClass = parentClass.getDeclaringClass();
        }
        return parentClass;
    }

    public static boolean isInstanceOfAny(Object obj, Class<?>...classes){
        if( LangUtil.isEmpty(classes)) {
            return false;
        }
        for(Class<?> cls :classes){
            if(cls.isInstance(obj)) {
                return true;
            }
        }
        return false;
    }


    public static Constructor<?> getConstructor(Class<?> clazz, int constructorIndex){
        Constructor<?>[] constroctors = clazz.getConstructors();
        if(constructorIndex>=constroctors.length){
            throw new NoSuchElementException("no constructor find. index: " + constructorIndex);
        }
        Constructor<?> targetConstructor = constroctors[constructorIndex];
        return targetConstructor;
    }

    public static <T> T newByConstructor(Class<T> clazz, int constructorIndex, Object...initargs){
        Constructor<?> constructor = getConstructor(clazz, constructorIndex);
        try {
            return (T) constructor.newInstance(initargs);
        } catch (Exception e) {
            throw new BaseException("new instance error, class:"+constructor.getDeclaringClass()+"");
        }
    }

    public static Object newInstance(Constructor<?> constructor, Object...initargs){
        try {
            return constructor.newInstance(initargs);
        } catch (Exception e) {
            throw new BaseException("new instance error, class:"+constructor.getDeclaringClass()+"");
        }
    }

    /**
     * 获取类 的所有Field,包含父类
     * @param clazz
     * @return
     */
    public static Map<String, Field> getAllFields(Class<?> clazz){
        Map<String, Field> maps = new LinkedHashMap<>();
        Class<?> searchType = clazz;
        while(!Object.class.equals(searchType) && searchType != null){
            Field[] fields = searchType.getDeclaredFields();
            for(Field field : fields){
                maps.put(field.getName(), field);
            }
            searchType = searchType.getSuperclass();
        }
        return maps;
    }

    public static MethodHandles.Lookup createMethodHandlesLookup(Class<?> clazz) {
        try {
            Constructor<MethodHandles.Lookup> constructor = MethodHandles.Lookup.class.getDeclaredConstructor(Class.class, int.class);
            constructor.setAccessible(true);
            MethodHandles.Lookup lookup = constructor.newInstance(clazz, MethodHandles.Lookup.PRIVATE);
            return lookup;
        } catch (Exception e) {
            throw new BaseException("create instance of MethodHandles.Lookup error for class: " + clazz);
        }
    }

    public static Object invokeDefaultMethod(MethodHandles.Lookup lookup, Method method, Object proxy, Object... args) {
        Object result;
        try {
            result = lookup.in(method.getDeclaringClass())
                    .unreflectSpecial(method, method.getDeclaringClass())
                    .bindTo(proxy)
                    .invokeWithArguments(args);
        }catch (Throwable e) {
            throw new BaseException("invoke default method error for : " + method, e);
        }
        return result;
    }


   public static boolean isProxy(Object proxy) {
        return AopUtils.isAopProxy(proxy);
   }

    public static Class<?> getUserClass(Class<?> clazz) {
        Assert.notNull(clazz, "Class must not be null");
        return isProxy(clazz) ? clazz.getSuperclass() : clazz;
    }

    /**
     * 属性对应 的 get、set 方法名称
     * @param name
     * @return
     */
    public static String methodToProperty(String name) {
        if (name.startsWith("is")) {
            name = name.substring(2);
        } else {
            if (!name.startsWith("get") && !name.startsWith("set")) {
                throw new BaseException("Error parsing property name '" + name + "'.  Didn't start with 'is', 'get' or 'set'.");
            }
            name = name.substring(3);
        }
        if (name.length() == 1 || name.length() > 1 && !Character.isUpperCase(name.charAt(1))) {
            name = name.substring(0, 1).toLowerCase(Locale.ENGLISH) + name.substring(1);
        }
        return name;
    }

}
